/**
 * Live GPS Tracking Application
 * Caching module which only uses a single file.
 *
 * Copyright 2009, Ivar Clemens
 */

package nl.ivarclemens.gpstrack.tile;

import java.io.*;
import javax.microedition.io.*;
import javax.microedition.io.file.*;
import java.util.Hashtable;

public class SingleFileCache {

    boolean cacheOpen = false;
    //file:///c:/Nokia/Images/Pictures/myfile.txt
    String cacheFile = "file:///c:/Gallery/tiles.png";

    private Hashtable availableTiles = new Hashtable();

    private FileConnection filecon = null;
    private DataInputStream dis = null;
    private DataOutputStream dos = null;

    public SingleFileCache()
    {
        try {
            filecon = (FileConnection) Connector.open(cacheFile, Connector.READ_WRITE);

            if(!filecon.exists())
                filecon.create();

            dis = filecon.openDataInputStream();
            dos = filecon.openDataOutputStream();

            this.buildHashTable();

            cacheOpen = true;
        } catch(Exception e) {
            cacheOpen = false;
            //throw new RuntimeException( e.getMessage() );
        }
    }

    public boolean canUse()
    {
        return cacheOpen;
    }

    /**
     * Retreives a specific segment of the datafile as byte[] array.
     */
    private byte[] getDataAt(long offset, long length) throws IOException
    {       
        byte[] buffer = new byte[(int)length];

        dis.reset();
        dis.read(buffer, (int) offset, (int) length);

        return buffer;
    }

    /**
     * Appends a segment and the associated metadata to the file.
     */
    public void appendData(String filename, byte[] buffer) throws IOException
    {
        // Store offset
        dis.reset();
        availableTiles.put(filename, new Integer(dis.available()));

        // Write tile
        dos.writeInt(buffer.length + filename.length() + 2);
        dos.writeShort(filename.length());
        dos.write(filename.getBytes());
        dos.write(buffer);
        dos.flush();
    }

    private void buildHashTable() throws IOException
    {
        availableTiles.clear();
        dis.reset();

        int fileLength = dis.available();
        int offset = 0;

        while(offset < fileLength) {
            int length = dis.readInt();
            int namelen = dis.readShort();

            byte[] buffer = new byte[(int)namelen];
            dis.read(buffer, 0, namelen);
            String filename = buffer.toString();

            dis.skipBytes(length - namelen - 2);

            availableTiles.put(filename, new Integer(offset));

            offset = offset + 4 + length;
        }
    }

    public boolean hasFile(String filename)
    {
        return availableTiles.containsKey(filename);
    }

    public byte[] getFile(String filename) throws IOException
    {
        if(availableTiles.containsKey(filename)) {
            Integer offset = (Integer) availableTiles.get(filename);

            dis.reset();
            dis.skipBytes(offset.intValue());

            int length = dis.readInt();
            short namelen = dis.readShort();

            dis.skipBytes(namelen);

            byte[] buffer = new byte[(int)length];
            dis.read(buffer, 0, length - namelen - 2);
            
            return buffer;
        } else {
            throw new IOException();
        }
    }
}
